package com.author.menubar;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Set;

import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
import javax.swing.border.LineBorder;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.EditorKit;
import javax.swing.text.html.HTML;
import javax.swing.text.html.HTMLDocument;
import javax.swing.text.html.HTMLEditorKit;

import com.author.surface.Surface;
import com.author.surface.TextPane;
import com.author.surface.TextPanel;

public class InsertPictureFrame extends JFrame {
	/*
	 * TextField is used to display the name of the file that has been selected
	 * by the user
	 */
	private JTextField				textField				= new JTextField();

	/* Picture label is used for showing a preview of the imported picture */
	private JLabel					pictureLabel			= new JLabel();

	/* File Name label is used to show the word "File" before the text field */
	private JLabel					fileNameLabel			= new JLabel("File");

	private JButton					browseBtn				= new JButton(
																	"Browse");														// Browse
																																	// button
																																	// for
																																	// choosing
																																	// file
	private JButton					okBtn					= new JButton("OK");													// OK
																																	// button
	private JButton					cancelBtn				= new JButton(
																	"Cancel");														// Cancel
																																	// button

	/** Dimensions of the picture frame */
	public static final int			PICTURE_FRAME_WIDTH		= 500;
	public static final int			PICTURE_FRAME_HEIGHT	= 350;

	/** Color of the picture frame */
	public static final Color		PICTURE_FRAME_COLOR		= Color.lightGray;

	/** X and Y locations of the picture dialog */
	public static final int			PICTURE_FRAME_X_LOC		= 300;
	public static final int			PICTURE_FRAME_Y_LOC		= 200;

	/* Width and height of the text field */
	private final int				textFieldWidth			= 300;
	private final int				textFieldHeight			= 25;

	/* X and Y locations of the text field */
	private final int				textFieldXLoc			= 50;
	private final int				textFieldYLoc			= 20;

	/* Width and height of the picture label */
	private final int				pictureLabelWidth		= 150;
	private final int				pictureLabelHeight		= 200;

	/* X and Y locations of the picture label */
	private final int				pictureLabelXLoc		= 150;
	private final int				pictureLabelYLoc		= 60;

	/* Picture Label background color */
	private final Color				pictureLabelBkgColor	= Color.WHITE;

	/*
	 * Width and height of the label displaying the word "File" before text
	 * field
	 */
	private final int				fileNameLabelWidth		= 50;
	private final int				fileNameLabelHeight		= 25;

	/* X and Y locations of the File Name Label */
	private final int				fileNameLabelXLoc		= 10;
	private final int				fileNameLabelYLoc		= 20;

	/* Width and height of all the three buttons */
	private final int				btnWidth				= 100;
	private final int				btnHeight				= 25;

	/* X and Y locations of the Browse button */
	private final int				browseBtnXLoc			= 370;
	private final int				browseBtnYLoc			= 20;

	/* X and Y locations of the ok button */
	private final int				okBtnXLoc				= 120;
	private final int				okBtnYLoc				= 275;

	/* X and Y locations of the cancel button */
	private final int				cancelBtnXLoc			= 230;
	private final int				cancelBtnYLoc			= 275;

	/* Title of the frame */
	private final String			Title					= "Insert Picture";

	/* Name of the file selected by the user */
	private static String			fileName				= "";

	/* Message for unknown graphics format */
	private static final String		UNKNW_GRAPHICS_FORMAT	= "Unknown graphics format. Supported formats are: JPEG/GIF/BMP/PNG";

	/*
	 * Name of valid picture file extensions. Currently only JPEG/BMP/GIF/PNG
	 * formats are supported
	 */
	private static final String[]	fileNameExt				= new String[] {
			"jpeg", "bmp", "gif", "png"					};
	private static Set<String>		fileNameExtTable		= new HashSet<String>();
	static {
		fileNameExtTable.add(fileNameExt[0]);
		fileNameExtTable.add(fileNameExt[1]);
		fileNameExtTable.add(fileNameExt[2]);
		fileNameExtTable.add(fileNameExt[3]);
	}

	public InsertPictureFrame() {
		/* Set frame title */
		this.setTitle(Title);

		/* Set size of the dialog */
		this.setPreferredSize(new Dimension(PICTURE_FRAME_WIDTH,
				PICTURE_FRAME_HEIGHT));
		this.setSize(this.getPreferredSize());

		/*
		 * Right now all widgets in this frame are manually placed. Hence the
		 * frame layout is set to null
		 */
		this.setLayout(null);

		/* Add widgets to Picture Frame */
		/* Add label indicating "File" name before the Text Field */
		this.fileNameLabel.setSize(fileNameLabelWidth, fileNameLabelHeight);
		this.fileNameLabel.setLocation(fileNameLabelXLoc, fileNameLabelYLoc);
		this.fileNameLabel.setName("File");
		this.add(fileNameLabel);

		/* Add text field to display the name of the file selected by the user */
		this.textField.setSize(textFieldWidth, textFieldHeight);
		this.textField.setPreferredSize(getSize());
		this.textField.setLocation(textFieldXLoc, textFieldYLoc);
		this.add(textField);

		/* Add browse button */
		this.browseBtn.setSize(btnWidth, btnHeight);
		this.browseBtn.setPreferredSize(getSize());
		this.browseBtn.setLocation(browseBtnXLoc, browseBtnYLoc);
		this.add(browseBtn);

		/* Add action listener for browse button */
		this.browseBtn.addActionListener(new BrowseAction());

		/*
		 * Add a picture label for displaying a preview of the picture selected
		 * by the user
		 */
		this.pictureLabel.setSize(pictureLabelWidth, pictureLabelHeight);
		this.pictureLabel.setLocation(pictureLabelXLoc, pictureLabelYLoc);
		this.pictureLabel.setBorder(new LineBorder(Color.BLACK, 1));

		this.pictureLabel.setOpaque(true);
		this.pictureLabel.setBackground(pictureLabelBkgColor);
		this.add(pictureLabel);

		/* Add ok button */
		this.okBtn.setSize(btnWidth, btnHeight);
		this.okBtn.setPreferredSize(getSize());
		this.okBtn.setLocation(okBtnXLoc, okBtnYLoc);
		this.add(okBtn);

		/* Add action listener for OK button */
		this.okBtn.addActionListener(new InsertPictureAction());

		/* Add cancel button */
		this.cancelBtn.setSize(btnWidth, btnHeight);
		this.cancelBtn.setPreferredSize(getSize());
		this.cancelBtn.setLocation(cancelBtnXLoc, cancelBtnYLoc);
		this.add(cancelBtn);

		/* Add action listener for cancel button */
		this.cancelBtn.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent ae) {
				InsertPictureFrame.this.dispose();
			}
		});

		/*
		 * Set location of the insert picture frame relative to the main
		 * application frame
		 */
		this.setLocationRelativeTo(Surface.getAppSurface());
		// this.setLocation(PICTURE_FRAME_X_LOC, PICTURE_FRAME_Y_LOC);
		this.setVisible(true);
	}

	private void setFileNameText(String fileName) {
		/* Ensure that the graphics file contains a valid extension */
		if (!(fileName.contains("."))) {
			return; // invalid file
		}

		String ext = fileName.substring(fileName.indexOf('.') + 1,
				fileName.length());
		if (!(fileNameExtTable.contains(ext))) {
			JOptionPane.showMessageDialog(this, UNKNW_GRAPHICS_FORMAT, null,
					JOptionPane.WARNING_MESSAGE);
			return;
		}

		/* Display the name of the file selected by the user in the text field */
		this.textField.setText(fileName);

		/* Set the icon of the picture label to the imported graphics picture */
		Image image;
		try {
			image = ImageIO.read(new File(fileName));
			Icon icon = new ImageIcon(image);
			pictureLabel.setIcon(icon);
		} catch (IOException ioe) {
			ioe.printStackTrace();
		}
	}

	class BrowseAction implements ActionListener {
		@Override
		public void actionPerformed(ActionEvent e) {
			if (!(e.getSource() instanceof JButton)) {
				return; // not fired from a button, ignore
			}

			JFileChooser fc = new JFileChooser(); // prompt user to choose file
			int returnVal = fc.showOpenDialog(null);
			if (returnVal == JFileChooser.APPROVE_OPTION) {
				File file = fc.getSelectedFile();
				fileName = file.getAbsolutePath();
			} else {
				fileName = ""; // user action is canceled
			}

			if (fileName != null) { // display file name in text field
				InsertPictureFrame.this.setFileNameText(fileName);
			}
		}
	}

	class InsertPictureAction implements ActionListener {
		/* Image size warning msg. */
		private static final String	IMAGE_SIZE_WARNING_MSG	= "Currently all image sizes are set to Width: 400 and Height: 400";

		@Override
		public void actionPerformed(ActionEvent ae) {
			if (!(ae.getSource() instanceof JButton)) {
				return;
			}

			if ((fileName == null) || (fileName == "")) {
				return; // Nothing to insert
			}

			EditorKit kit = TextPane.getTextPaneEditorKit();
			if (!(kit instanceof HTMLEditorKit)) {
				return;
			}

			Document doc = TextPane.getTextPaneDocument();
			if (!(doc instanceof HTMLDocument)) {
				return;
			}

			try {
				/*
				 * Inform user that currently all image sizes are fixed at
				 * 400x400 pixels
				 */
				JOptionPane.showMessageDialog(InsertPictureFrame.this,
						IMAGE_SIZE_WARNING_MSG, null,
						JOptionPane.WARNING_MESSAGE);
				/* Insert picture image */
				String htmlText = "<HTML><BODY><IMG SRC = file://" + fileName
						+ " WIDTH = 400 HEIGHT = 400></IMG></BODY></HTML>";
				int pos = TextPane.getDot();
				((HTMLEditorKit) kit).insertHTML((HTMLDocument) doc, pos,
						htmlText, 1, 0, null);
				InsertPictureFrame.this.dispose();
			} catch (BadLocationException ble) {
				ble.printStackTrace();
			} catch (IOException ioe) {
				ioe.printStackTrace();
			}
		}
	}
}
